// $Id: interface_def.cpp 2 2009-09-02 08:47:42Z joseph2002 $
/*
 * Copyright 2009 Joseph Wu
 * Distributed under the Boost Software License, Version 1.0.
 * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
 *
 * For more information, see http://xpcomplus.sourceforge.net
 */

#include <iostream>
#include <xpcom/ptr.hpp>
#include <xpcom/memory.hpp>
#include <xpcom/result_code.hpp>
#include <xpcom/string.hpp>
#include <xpcom/uuid.hpp>
#include "interface_def.hpp"

using namespace xpcom;

namespace {
int count = 0;
}

int X_count()
{
    return count;
}

void X_count(int n)
{
    count = n;
}

class X : public IA, public IC
{
public:
    X() : ref_(0), n_(0), a_(0), b_(0), c_(0)
    {
        std::cout << "X()" << std::endl;
        ++count;
    }

    virtual ~X()
    {
        std::cout << "~X()" << std::endl;
        --count;
    }

    static void* operator new(std::size_t n)
    {
        return memory::alloc_data(n);
    }

    static void operator delete(void* p, std::size_t /*n*/)
    {
        memory::free_data(p);
    }

    XPCOM_IMETHOD query_interface(const uuid& iid, void** obj)
    {
        std::cout << "X::qi(" << iid << ")" << std::endl;
        if (!obj)
            return NS_ERROR_NULL_POINTER;
        *obj = 0;

        if (iid == typeid_of<interface>()) {
            *obj = static_cast<IA*>(this);
        } else if (iid == typeid_of<IBase>()) {
            *obj = static_cast<IA*>(this);
        } else if (iid == typeid_of<IA>()) {
            *obj = static_cast<IA*>(this);
        } else if (iid == typeid_of<IB>()) {
            *obj = static_cast<IC*>(this);
        } else if (iid == typeid_of<IC>()) {
            *obj = static_cast<IC*>(this);
        } else {
            return NS_ERROR_NO_INTERFACE;
        }

        if (*obj)
            add_ref();

        return NS_OK;
    }

    XPCOM_IMETHOD_(refcnt_t) add_ref()
    {
        ++ref_;
        std::cout << "X::add_ref(" << ref_ << ")" << std::endl;
        return ref_;
    }

    XPCOM_IMETHOD_(refcnt_t) release()
    {
        --ref_;
        std::cout << "X::release(" << ref_ << ")" << std::endl;
        if (ref_ == 0)
            delete this;
        return ref_;
    }

    virtual refcnt_t ref()
    {
        return ref_;
    }

    virtual int getN()
    {
        return n_;
    }

    virtual void setN(int n)
    {
        n_ = n;
    }

    virtual int getA()
    {
        return a_;
    }

    virtual void setA(int a)
    {
        a_ = a;
    }

    virtual int getB()
    {
        return b_;
    }

    virtual void setB(int b)
    {
        b_ = b;
    }

    virtual int getC()
    {
        return c_;
    }

    virtual void setC(int c)
    {
        c_ = c;
    }

    refcnt_t ref() const
    {
        return ref_;
    }

private:
    refcnt_t ref_;
    int n_, a_, b_, c_;
};

IBase* X_make_instance()
{
    return static_cast<IA*>(new X);
}
